home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / nojet / db.bas < prev    next >
BASIC Source File  |  1995-03-06  |  8KB  |  289 lines

  1. DefInt A-Z
  2. Option Explicit
  3. Option Compare Text
  4. Type Contact
  5.     Salutation  As String * 10
  6.     LastName    As String * 30
  7.     FirstName   As String * 20
  8.     Company     As String * 30
  9.     Title       As String * 30
  10.     Address_1   As String * 30
  11.     Address_2   As String * 30
  12.     City        As String * 30
  13.     State       As String * 30
  14.     ZipCode     As String * 10
  15.     Country     As String * 30
  16.     Phone       As String * 15
  17.     Extension   As String * 10
  18.     Fax         As String * 15
  19.     EMail       As String * 30
  20.     Link        As Long
  21. End Type
  22. Type ContactIndex
  23.     sKey        As String * 50
  24.     lRecNo      As Long
  25. End Type
  26. Type Comment
  27.     Text        As String * 252
  28.     lRecNo      As Long
  29. End Type
  30.  
  31. 'Handles for data, comment
  32. '  and index files
  33. Global hDat As Integer
  34. Global hCmt As Integer
  35. Global hIdx As Integer
  36. Global sNull As String
  37.  
  38. Declare Function llseek Lib "Kernel" Alias "_llseek" (ByVal hFile As Integer, ByVal lOffset As Long, ByVal iOrigin As Integer) As Long
  39. Declare Function lread Lib "Kernel" Alias "_lread" (ByVal hFile As Integer, lpBuffer As Any, ByVal wBytes As Integer) As Integer
  40. Declare Function lwrite Lib "Kernel" Alias "_lwrite" (ByVal hFile As Integer, lpBuffer As Any, ByVal wBytes As Integer) As Integer
  41.  
  42. Function AppPath$ ()
  43.  
  44.     Static sPath As String
  45.  
  46.     'Just do this once
  47.     If Len(sPath) = 0 Then
  48.         sPath = App.Path
  49.         If Asc(Right$(sPath, 1)) <> 92 Then
  50.             sPath = sPath & "\"
  51.         End If
  52.     End If
  53.  
  54.     AppPath$ = sPath
  55.  
  56. End Function
  57.  
  58. Sub CommentDelete (lRecNo As Long)
  59.  
  60.     Dim udtComment As Comment
  61.  
  62.     'See comments in ContactDelete
  63.     Get hCmt, 1, udtComment
  64.     If udtComment.lRecNo = 0 Then
  65.         udtComment.lRecNo = -lRecNo
  66.     End If
  67.     Put hCmt, lRecNo, udtComment
  68.     udtComment.lRecNo = -lRecNo
  69.     Put hCmt, 1, udtComment
  70.  
  71. End Sub
  72.  
  73. Sub ContactDelete (lRecNo As Long)
  74.  
  75.     Dim udtIndex As ContactIndex
  76.     Dim udtContact As Contact
  77.  
  78.     'Examine header record. If its record pointer
  79.     '  is zero, set deleted record to point to itself.
  80.     '  Otherwise, copy header rec to lRecNo (negative
  81.     '  lRecNo indicates a deleted record)
  82.     Get hIdx, lRecNo, udtIndex
  83.     Get hDat, 1, udtContact
  84.     If udtContact.Link = 0 Then
  85.         udtContact.Link = -udtIndex.lRecNo
  86.     End If
  87.     Put hDat, udtIndex.lRecNo, udtContact
  88.     'Set header to point to lRecNo
  89.     udtContact.Link = -udtIndex.lRecNo
  90.     Put hDat, 1, udtContact
  91.  
  92. End Sub
  93.  
  94. Function FileOpen (sFileName As String, iRecLen As Integer)
  95.  
  96.     Dim iHandle As Integer
  97.     Dim sTemp As String
  98.     Dim udtIndex As ContactIndex
  99.  
  100.     iHandle = FreeFile
  101.     Open sFileName For Random Shared As iHandle Len = iRecLen
  102.  
  103.     'If we're not opening the index...
  104.     If iRecLen <> Len(udtIndex) Then
  105.         'Create header record if none exists
  106.         If LOF(iHandle) = 0 Then
  107.             sTemp = String$(iRecLen - 2, 0)
  108.             Put iHandle, 1, sTemp
  109.         End If
  110.     End If
  111.     FileOpen = iHandle
  112.  
  113. End Function
  114.  
  115. Function FreeComment& (hFile As Integer)
  116.  
  117.     Dim lRecNo As Long
  118.     Dim udtComment As Comment
  119.  
  120.     'Get pointer to next free record
  121.     Get hFile, 1, udtComment
  122.     'If it's not zero...
  123.     If udtComment.lRecNo Then
  124.         lRecNo = Abs(udtComment.lRecNo)
  125.         'Get that record's pointer
  126.         Get hFile, lRecNo, udtComment
  127.         '  and save it in rec #1
  128.         Put hFile, 1, udtComment
  129.     Else
  130.         'Extend file
  131.         lRecNo = LOF(hFile) \ Len(udtComment) + 1
  132.     End If
  133.     FreeComment& = lRecNo
  134.  
  135. End Function
  136.  
  137. Function FreeContact& (hFile As Integer)
  138.  
  139.     Dim lRecNo As Long
  140.     Dim udtContact As Contact
  141.  
  142.     'Get pointer to next free record
  143.     Get hFile, 1, udtContact
  144.     'If it's not zero...
  145.     If udtContact.Link Then
  146.         lRecNo = Abs(udtContact.Link)
  147.         'Get that record's pointer
  148.         Get hFile, lRecNo, udtContact
  149.         'and save it in rec #1
  150.         Put hFile, 1, udtContact
  151.     Else
  152.         'Extend file
  153.         lRecNo = LOF(hFile) \ Len(udtContact) + 1
  154.     End If
  155.     FreeContact& = lRecNo
  156.  
  157. End Function
  158.  
  159. Sub IndexDelete (lRecNo As Long)
  160.  
  161.     Dim hDOS As Integer
  162.     Dim iLen As Integer
  163.     Dim nBytes As Integer
  164.     Dim lPos As Long
  165.     Dim lRecs As Long
  166.     Dim udtIndex As ContactIndex
  167.  
  168.     iLen = Len(udtIndex)
  169.     lRecs = LOF(hIdx) \ iLen
  170.     hDOS = FileAttr(hIdx, 2)
  171.     If lRecNo < lRecs Then
  172.         'Dim an array large enough to contain all
  173.         '  index entries following lRecNo
  174.         ReDim udtIdxArray(1 To (lRecs - lRecNo)) As ContactIndex
  175.         'Use API calls to fill array
  176.         lPos = llseek(hDOS, (iLen * lRecNo), 0)
  177.         nBytes = lread(hDOS, udtIdxArray(1), UBound(udtIdxArray) * iLen)
  178.         'Move file pointer up one record
  179.         lPos = llseek(hDOS, (lPos - iLen), 0)
  180.         'Write array contents
  181.         nBytes = lwrite(hDOS, udtIdxArray(1), UBound(udtIdxArray) * iLen)
  182.     End If
  183.     'Seek to LOF - 1
  184.     lPos = llseek(hDOS, (LOF(hIdx) - iLen), 0)
  185.     'Write zero bytes to truncate file
  186.     nBytes = lwrite(hDOS, ByVal sNull$, 0)
  187.  
  188. End Sub
  189.  
  190. Sub IndexInsert (udtIndex As ContactIndex)
  191.  
  192.     Dim hDOS As Integer
  193.     Dim iLen As Integer
  194.     Dim nBytes As Integer
  195.     Dim lPos As Long
  196.     Dim lRecNo As Long
  197.     Dim lRecs As Long
  198.     Dim udtTemp As ContactIndex
  199.  
  200.     iLen = Len(udtIndex)
  201.     lRecs = LOF(hIdx) \ iLen
  202.     If lRecs Then
  203.         'Find first index entry greater than
  204.         '  insertion key (okay, I know a loop
  205.         '  is low-tech; whaddya want for free?!)
  206.         For lRecNo = 1 To lRecs
  207.             Get hIdx, lRecNo, udtTemp
  208.             If udtTemp.sKey > udtIndex.sKey Then
  209.                 Exit For
  210.             End If
  211.         Next
  212.         'If we need to insert our entry somewhere before
  213.         '  the end, copy a block of records down one position
  214.         '  (see comments in IndexDelete for details)
  215.         If lRecNo <= lRecs Then
  216.             hDOS = FileAttr(hIdx, 2)
  217.             ReDim udtIdxArray(1 To (lRecs - lRecNo + 1)) As ContactIndex
  218.             lPos = llseek(hDOS, (iLen * (lRecNo - 1)), 0)
  219.             nBytes = lread(hDOS, udtIdxArray(1), UBound(udtIdxArray) * iLen)
  220.             lPos = llseek(hDOS, (lPos + iLen), 0)
  221.             nBytes = lwrite(hDOS, udtIdxArray(1), UBound(udtIdxArray) * iLen)
  222.         End If
  223.     Else
  224.         lRecNo = 1
  225.     End If
  226.     'lRecNo will point past end of file if
  227.     '  udtIndex.sKey is greater than all
  228.     '  existing keys
  229.     Put hIdx, lRecNo, udtIndex
  230.  
  231. End Sub
  232.  
  233. Sub IndexRebuild ()
  234.  
  235.     Dim I As Integer
  236.     Dim udtContact As Contact
  237.     Dim udtIndex As ContactIndex
  238.  
  239.     Kill AppPath$() & "contacts.idx"
  240.     hDat = FileOpen(AppPath$() & "contacts.dat", Len(udtContact))
  241.     hIdx = FileOpen(AppPath$() & "contacts.idx", Len(udtIndex))
  242.  
  243.     For I = 2 To LOF(hDat) \ Len(udtContact)
  244.         Get hDat, I, udtContact
  245.         If udtContact.Link >= 0 Then
  246.             udtIndex.sKey = udtContact.LastName & udtContact.FirstName
  247.             udtIndex.lRecNo = I
  248.             Call IndexInsert(udtIndex)
  249.         End If
  250.     Next
  251.     Close
  252.  
  253. End Sub
  254.  
  255. Function IndexSearch (sTarget As String)
  256.  
  257.     Dim I As Integer
  258.     Dim iLen As Integer
  259.     Dim iMin As Integer
  260.     Dim iMax As Integer
  261.     Dim iResult As Integer
  262.     Dim udtIndex As ContactIndex
  263.  
  264.     'Perform case-insensitive binary search
  265.     ' for sTarget
  266.     iMin = 1
  267.     iMax = LOF(hIdx) \ Len(udtIndex)
  268.     iLen = Len(sTarget)
  269.     Do
  270.         I = (iMin + iMax) \ 2
  271.         Get hIdx, I, udtIndex
  272.         'Only as many characters of sKey as
  273.         '  sTarget is long
  274.         If Left$(udtIndex.sKey, iLen) = sTarget Then
  275.             iResult = I
  276.             Exit Do
  277.         ElseIf udtIndex.sKey > sTarget Then
  278.             iMax = I - 1
  279.         Else
  280.             iMin = I + 1
  281.         End If
  282.     Loop While iMax >= iMin
  283.  
  284.     'Return location (or zero if not found)
  285.     IndexSearch = iResult
  286.  
  287. End Function
  288.  
  289.